﻿/* 
This file is part of Ingo Karstein's Long Path Support project

**Do not remove this comment**

Please see the project homepage at CodePlex:
  http://longpathsupport.codeplex.com/

Please see my blog:
  http://ikarstein.wordpress.com

This code is used in the project "RoboPowerCopy"
  http://robopowercopy.codeplex.com

Licence: GPLv2
    Ingo Karstein's SharePoint 2010 Custom Ribbon Demo
    Copyright (C) 2011  Ingo Karstein, ikarstein@hotmail.com

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security;

public class LongDirectoryInfo
{
    private string _fullname;
    private string _name;
    private int _prefixLen = 0;
    private DateTime _lastWriteTime;
    private DateTime _lastWriteTimeUtc;
    private DateTime _lastAccessTime;
    private DateTime _lastAccessTimeUtc;
    private DateTime _creationTime;
    private DateTime _creationTimeUtc;

    [SecuritySafeCritical]
    public LongDirectoryInfo(string directoryName)
    {
        _fullname = LongPathSupport.GetFullName(directoryName);
        if( string.IsNullOrEmpty(_fullname) )
            throw new System.IO.IOException("Could not determine full name");

        if( !_fullname.StartsWith(@"\\?\") )
        {
            if( _fullname.StartsWith(@"\\") )
            {
                _fullname = @"\\?\UNC\" + _fullname.Substring(2);
                _prefixLen = 8;
            }
            else
            {
                _fullname = @"\\?\" + _fullname;
                _prefixLen = 4;
            }
        }
        else
        {
            if( _fullname.StartsWith(@"\\?\UNC\") )
                _prefixLen = 8;
            else
                _prefixLen = 4;
        }

        //if (_fullname.Length - _prefixLen == 3)
        //{
        //    _fullname = _fullname.Substring(_prefixLen);
        //}

        if( string.IsNullOrEmpty(_fullname) )
            throw new Exception(LongPathSupport.LastError());

        _name = System.IO.Path.GetFileName(_fullname);

        Refresh();
    }

    [SecuritySafeCritical]
    public LongDirectoryInfo[] GetDirectories(string searchPattern)
    {
        List<LongDirectoryInfo> ret = new List<LongDirectoryInfo>();
        searchPattern = "^" + System.Text.RegularExpressions.Regex.Escape(searchPattern).Replace("\\*", ".*").Replace("\\?", ".") + "$";
        System.Text.RegularExpressions.Regex r = new System.Text.RegularExpressions.Regex(searchPattern);
        foreach( string dir in LongPathSupport.FindFilesAndDirs(_fullname, LongPathSupport.FindType.Directories, false) )
        {
            LongDirectoryInfo dir2 = new LongDirectoryInfo(dir);
            if( r.IsMatch(dir2.Name) )
                ret.Add(dir2);
        }
        return ret.ToArray();
    }

    [SecuritySafeCritical]
    public LongDirectoryInfo[] GetDirectories()
    {
        return GetDirectories("*");
    }

    [SecuritySafeCritical]
    public LongFileInfo[] GetFiles(string searchPattern)
    {
        List<LongFileInfo> ret = new List<LongFileInfo>();
        searchPattern = "^" + System.Text.RegularExpressions.Regex.Escape(searchPattern).Replace("\\*", ".*").Replace("\\?", ".") + "$";
        System.Text.RegularExpressions.Regex r = new System.Text.RegularExpressions.Regex(searchPattern);
        foreach( string dir in LongPathSupport.FindFilesAndDirs(_fullname, LongPathSupport.FindType.Files, false) )
        {
            LongFileInfo lfi = new LongFileInfo(dir);
            if( r.IsMatch(lfi.Name) )
                ret.Add(new LongFileInfo(dir));
        }
        return ret.ToArray();
    }

    [SecuritySafeCritical]
    public LongFileInfo[] GetFiles()
    {

        return GetFiles("*");
    }

    public string FullName
    {
        get
        {
            return _fullname.Substring(_prefixLen);
        }
    }

    public string FullQualifiedName
    {
        get
        {
            return _fullname;
        }
    }

    public string Name
    {
        get
        {
            return this._name;
        }
    }

    public bool Exists
    {
        [SecuritySafeCritical]
        get
        {
            return LongPathSupport.DirectoryExists(_fullname);
        }
    }

    public void Delete(bool recursive)
    {
        if( recursive )
        {
            List<string> files = LongPathSupport.FindFilesAndDirs(_fullname, LongPathSupport.FindType.Files, true);
            foreach( string s in files )
                LongPathSupport.DeleteFile(s);

            List<string> dirs = LongPathSupport.FindFilesAndDirs(_fullname, LongPathSupport.FindType.Directories, true);
            foreach( string s in dirs )
                LongPathSupport.DeleteDirectory(s, true);
        }

        LongPathSupport.DeleteDirectory(_fullname);
    }

    public DateTime LastWriteTime
    {
        get
        {
            return _lastWriteTime;
        }
        set
        {
            _lastWriteTime = value;
            if( !FileTimeHelper.SetDirectoryTimesUtc(_fullname, null, null, _lastWriteTime) )
                throw new System.IO.IOException("Could not set LastWriteTime");
        }
    }
    public DateTime LastWriteTimeUtc
    {
        get
        {
            return _lastWriteTimeUtc;
        }
        set
        {
            _lastWriteTimeUtc = value;
            if( !FileTimeHelper.SetDirectoryTimesUtc(_fullname, null, null, _lastWriteTimeUtc) )
                throw new System.IO.IOException("Could not set LastWriteTimeUtc");
        }
    }
    public DateTime LastAccessTime
    {
        get
        {
            return _lastAccessTime;
        }
        set
        {
            _lastAccessTime = value;
            if( !FileTimeHelper.SetDirectoryTimesUtc(_fullname, null, _lastAccessTime, null) )
                throw new System.IO.IOException("Could not set LastAccessTime");
        }
    }
    public DateTime LastAccessTimeUtc
    {
        get
        {
            return _lastAccessTimeUtc;
        }
        set
        {
            _lastAccessTimeUtc = value;
            if( !FileTimeHelper.SetDirectoryTimesUtc(_fullname, null, _lastAccessTimeUtc, null) )
                throw new System.IO.IOException("Could not set LastAccessTimeUtc");
        }
    }
    public DateTime CreationTime
    {
        get
        {
            return _creationTime;
        }
        set
        {
            _creationTime = value;
            if( !FileTimeHelper.SetDirectoryTimesUtc(_fullname, _creationTime, null, null) )
                throw new System.IO.IOException("Could not set CreationTime");
        }
    }
    public DateTime CreationTimeUtc
    {
        get
        {
            return _creationTimeUtc;
        }
        set
        {
            _creationTimeUtc = value;
            if( !FileTimeHelper.SetDirectoryTimesUtc(_fullname, _creationTimeUtc, null, null) )
                throw new System.IO.IOException("Could not set CreationTimeUtc");
        }
    }

    public void Refresh()
    {
        if( !Exists )
        {
            DateTime minUtc = new DateTime(1601, 01, 01, 00, 00, 00, 00, DateTimeKind.Utc);
            DateTime minLocal = minUtc.ToLocalTime();
            _creationTime = _lastAccessTime = _lastWriteTime = minLocal;
            _creationTimeUtc = _lastAccessTimeUtc = _lastWriteTimeUtc = minUtc;
        }
        else
        {
            if( !FileTimeHelper.GetDirectoryTimes(_fullname, out _creationTime, out _lastAccessTime, out _lastWriteTime) )
                throw new System.IO.IOException("Could not get file times");
            if( !FileTimeHelper.GetDirectoryTimesUtc(_fullname, out _creationTimeUtc, out _lastAccessTimeUtc, out _lastWriteTimeUtc) )
                throw new System.IO.IOException("Could not get file times");
        }
    }

    public LongDirectoryInfo Parent
    {
        [SecuritySafeCritical]
        get
        {
            string fullPath = _fullname;
            if( ( fullPath.Length > 3 ) && ( fullPath.EndsWith(System.IO.Path.DirectorySeparatorChar.ToString()) || fullPath.EndsWith(System.IO.Path.AltDirectorySeparatorChar.ToString()) ) )
            {
                fullPath = fullPath.Substring(0, fullPath.Length - 1);
            }

            string directoryName = LongPathSupport.GetDirectoryName(fullPath);
            if( directoryName == null )
            {
                return null;
            }

            LongDirectoryInfo info = new LongDirectoryInfo(directoryName);
            //new FileIOPermission(FileIOPermissionAccess.PathDiscovery | FileIOPermissionAccess.Read, info.demandDir, false, false).Demand();
            return info;
        }

    }

    public void Create()
    {
        try
        {
            if( !Parent.Exists )
                Parent.Create();
        }
        catch
        {
            throw new System.IO.IOException("Could not create directory");
        }

        if( !LongPathSupport.CreateDirectory(_fullname) )
            throw new System.IO.IOException("Could not create directory");
    }

    public static bool TypeAvailable()
    {
        return true;
    }
}

